/*
 * @Description  :
 * @Version      : 0.1
 * @Company      : V-Think Development Team
 * @Author       : KiraVerSace@yeah.net
 * @Date         : 2025-01-04 01:27:51
 */
#include <xCommon.h>
#include <stdio.h>

/*--------- freeRTOS --------*/
volatile uint32_t freeRTOSRunTimeCount = 0UL;
void freeRTOSAssertCalled(const char *fileName, int fileLine) // 实现freeRTOS中的断言回调函数FreeRTOSConfig_Default.h/L214
{
    Serial.printf("freeRTOS Error:%s, %d\r\n", fileName, fileLine);
}

/*---------- Log ----------*/
void printPrefix(Print *_logOutput, int logLevel);
void printSuffix(Print *_logOutput, int logLevel);
void printTimestamp(Print *_logOutput);
void printLogLevel(Print *_logOutput, int logLevel);

/*---------- xCommonInit ----------*/
XStoreParameterT xParameter;
XSensorDataT     xSensorData;
QueueHandle_t    xSensorDataQueue;
datadacCalibrationTableT dacCalibrationTable[DAC_CALIBRATION_TABLE_SIZE];

void xCommonInit(void)
{
    __HAL_RCC_AFIO_CLK_ENABLE(); // 使能复用功能时钟,释放PB4
    __HAL_AFIO_REMAP_SWJ_NONJTRST();

    Serial.begin(115200);
    Serial.print(TERMINAL_CLEAR);
    Serial.printf(">>System start... [%d]MHz\r\n", SystemCoreClock / 1000000);
    Serial.println(">>---------------------VThink Development Team-------------------------<<\r\n");

    xLog.begin(LOG_LEVEL_VERBOSE, &Serial, true, true);
    xLog.setShowLevel(false); // Do not show loglevel, do in the prefix
    xLog.setPrefix(printPrefix);

    /* 初始化EEPROM */
    EEPROM.begin();
    if (EEPROM.read(0) != EEPROM_INIT_FLAG)
    {
        EEPROM.write(0, EEPROM_INIT_FLAG);
        xLog.warning("EEPROM first init, set to default configuration....\r\n");

        xParameter.modbusAddress     = 3;
        xParameter.baudRate          = BAUD_RATE_9600;
        xParameter.parity            = PARITY_NONE;
        xParameter.stopBit           = STOP_BITS_1;

        xParameter.dacCalibrationA0  = 100;
        xParameter.dacCalibrationA1  = 1000;
        xParameter.dacCalibrationA2  = 2000;
        xParameter.dacCalibrationA3  = 3000;
        xParameter.dacCalibrationA4  = 4000;
        xParameter.dacCalibrationA5  = 5000;
        xParameter.dacCalibrationA6  = 6000;
        xParameter.dacCalibrationA7  = 7000;
        xParameter.dacCalibrationA8  = 8000;
        xParameter.dacCalibrationA9  = 9000;
        xParameter.dacCalibrationA10 = 9900;
        xParameter.dacCalibrationB0  = 100;
        xParameter.dacCalibrationB1  = 1000;
        xParameter.dacCalibrationB2  = 2000;
        xParameter.dacCalibrationB3  = 3000;
        xParameter.dacCalibrationB4  = 4000;
        xParameter.dacCalibrationB5  = 5000;
        xParameter.dacCalibrationB6  = 6000;
        xParameter.dacCalibrationB7  = 7000;
        xParameter.dacCalibrationB8  = 8000;
        xParameter.dacCalibrationB9  = 9000;
        xParameter.dacCalibrationB10 = 9900;

        xParameter.defaultCH1Output   = 0;   // CH1默认输出值
        xParameter.defaultCH2Output   = 0;   // CH2默认输出值
        xParameter.defaultRelayOutput = 0;   // Relay默认输出值

        // 初始化默认校准表
        updateDacCalibrationTable();

        EEPROM.put(1, xParameter);
    }
    else
    {
        EEPROM.get(1, xParameter);

        // 使用xParameter中的校准参数给全局dacCalibrationTable赋值
        updateDacCalibrationTable();

        xLog.info("EEPROM was initialized, load parameters....\r\n");
        printParameterTable();
    }

    xSensorData.mvCH1 = 0;
    xSensorData.mvCH2 = 0;
    xSensorData.relayOutput = 0; // 初始继电器状态为0

    xSensorDataQueue = xQueueCreate(10, sizeof(XSensorDataT));

    if (!IWatchdog.isEnabled())
    {
        IWatchdog.begin(5000UL * 1000UL);
        if (IWatchdog.isEnabled())
        {
            xLog.info("Watchdog initialized, timeout = [5000]ms\r\n");
        }
        else
        {
            xLog.error("Watchdog init failed\r\n");
        }
    }
    else
    {
        xLog.warning("Watchdog already enabled\r\n");
    }
    IWatchdog.reload();
}

/*----------------------------------------------------------------*/
void printPrefix(Print *_logOutput, int logLevel)
{
    printTimestamp(_logOutput);
    printLogLevel(_logOutput, logLevel);
}

void printTimestamp(Print *_logOutput)
{
    // Division constants
    const unsigned long MSECS_PER_SEC = 1000;
    const unsigned long SECS_PER_MIN  = 60;
    const unsigned long SECS_PER_HOUR = 3600;
    const unsigned long SECS_PER_DAY  = 86400;

    // Total time
    const unsigned long msecs = millis();
    const unsigned long secs = msecs / MSECS_PER_SEC;

    // Time in components
    const unsigned long MiliSeconds = msecs % MSECS_PER_SEC;
    const unsigned long Seconds = secs % SECS_PER_MIN;
    const unsigned long Minutes = (secs / SECS_PER_MIN) % SECS_PER_MIN;
    const unsigned long Hours = (secs % SECS_PER_DAY) / SECS_PER_HOUR;

    // Time as string
    char timestamp[20];
    sniprintf(timestamp, sizeof(timestamp), "%02d:%02d:%02d.%03d ", Hours, Minutes, Seconds, MiliSeconds);
    _logOutput->print(timestamp);
}

void printLogLevel(Print *_logOutput, int logLevel)
{
    switch (logLevel)
    {
        default:
        case 0:_logOutput->print("[SIL  ] > "); break;
        case 1:_logOutput->print("[FATAL] > "); break;
        case 2:_logOutput->print("[ERROR] > "); break;
        case 3:_logOutput->print("[WARN] > "); break;
        case 4:_logOutput->print("[INFO] > "); break;
        case 5:_logOutput->print("[TRACE] > "); break;
        case 6:_logOutput->print("[VERB ] > "); break;
    }
}

/*---------- 参数表格打印函数 ----------*/
void printParameterTable(void)
{
    char valueStr[64];
    char inputStr[32], ch1Str[32], ch2Str[64];

    xLog.info("-----------------------------------------------------------------------------\r\n");
    xLog.info("                           System Parameters Table                          \r\n");
    xLog.info("-----------------------------------------------------------------------------\r\n");

    // Modbus配置参数
    xLog.info("┌─────────────────────────────────────────────────────────────────────────┐\r\n");
    xLog.info("│                           Modbus Configuration                          │\r\n");
    xLog.info("├──────────────────────┬──────────────────────────────────────────────────┤\r\n");
    xLog.info("│ Parameter            │ Value                                            │\r\n");
    xLog.info("├──────────────────────┼──────────────────────────────────────────────────┤\r\n");
    sprintf(valueStr, "%-48d", xParameter.modbusAddress);
    xLog.info("│ Modbus Address       │ %s │\r\n", valueStr);
    sprintf(valueStr, "%-48d", xParameter.baudRate);
    xLog.info("│ Baud Rate            │ %s │\r\n", valueStr);
    sprintf(valueStr, "%-48d", xParameter.parity);
    xLog.info("│ Parity               │ %s │\r\n", valueStr);
    sprintf(valueStr, "%-48d", xParameter.stopBit);
    xLog.info("│ Stop Bit             │ %s │\r\n", valueStr);
    sprintf(valueStr, "%-48d", xParameter.defaultCH1Output);
    xLog.info("│ Default CH1 Output   │ %s │\r\n", valueStr);
    sprintf(valueStr, "%-48d", xParameter.defaultCH2Output);
    xLog.info("│ Default CH2 Output   │ %s │\r\n", valueStr);
    sprintf(valueStr, "%-48d", xParameter.defaultRelayOutput);
    xLog.info("│ Default Relay Output │ %s │\r\n", valueStr);
    xLog.info("└──────────────────────┴──────────────────────────────────────────────────┘\r\n");

    // DAC校准表 (合并CH1和CH2)
    xLog.info("┌──────────────────────────────────────────────────-───────────────────────┐\r\n");
    xLog.info("│                        DAC Calibration Table (mV)                        │\r\n");
    xLog.info("├──────────────────┬─────────────────────┬─────────────────────────────────┤\r\n");
    xLog.info("│ Input Value      │ CH1 Output          │ CH2 Output                      │\r\n");
    xLog.info("├──────────────────┼─────────────────────┼─────────────────────────────────┤\r\n");
    sprintf(inputStr, "%-16d", 100);   sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA0);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB0);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 1000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA1);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB1);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 2000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA2);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB2);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 3000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA3);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB3);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 4000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA4);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB4);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 5000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA5);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB5);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 6000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA6);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB6);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 7000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA7);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB7);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 8000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA8);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB8);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 9000);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA9);  sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB9);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    sprintf(inputStr, "%-16d", 9900);  sprintf(ch1Str, "%-19d", xParameter.dacCalibrationA10); sprintf(ch2Str, "%-31d", xParameter.dacCalibrationB10);
    xLog.info("│ %s │ %s │ %s │\r\n", inputStr, ch1Str, ch2Str);
    xLog.info("└──────────────────┴─────────────────────┴─────────────────────────────────┘\r\n");

    xLog.info("-----------------------------------------------------------------------------\r\n");
}

/*---------- 更新DAC校准表函数 ----------*/
void updateDacCalibrationTable(void)
{
    dacCalibrationTable[0]  = {100,  xParameter.dacCalibrationA0,  xParameter.dacCalibrationB0};
    dacCalibrationTable[1]  = {1000, xParameter.dacCalibrationA1,  xParameter.dacCalibrationB1};
    dacCalibrationTable[2]  = {2000, xParameter.dacCalibrationA2,  xParameter.dacCalibrationB2};
    dacCalibrationTable[3]  = {3000, xParameter.dacCalibrationA3,  xParameter.dacCalibrationB3};
    dacCalibrationTable[4]  = {4000, xParameter.dacCalibrationA4,  xParameter.dacCalibrationB4};
    dacCalibrationTable[5]  = {5000, xParameter.dacCalibrationA5,  xParameter.dacCalibrationB5};
    dacCalibrationTable[6]  = {6000, xParameter.dacCalibrationA6,  xParameter.dacCalibrationB6};
    dacCalibrationTable[7]  = {7000, xParameter.dacCalibrationA7,  xParameter.dacCalibrationB7};
    dacCalibrationTable[8]  = {8000, xParameter.dacCalibrationA8,  xParameter.dacCalibrationB8};
    dacCalibrationTable[9]  = {9000, xParameter.dacCalibrationA9,  xParameter.dacCalibrationB9};
    dacCalibrationTable[10] = {9900, xParameter.dacCalibrationA10, xParameter.dacCalibrationB10};
}
